package engine;

import java.util.List;

import org.lwjgl.input.Mouse;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

public class EventHandler {
	private World world;
	private FrameBuffer buffer;
	private Universe universe;
	private List<Planet> planets;
	
	private Planet selectedPlanet;
	private Planet focusedPlanet;
	
	private int srcDragId = -1;

	public EventHandler(World w, FrameBuffer b, Universe universe) {
		world = w;
		buffer = b;
		this.universe = universe;
		this.planets = universe.getPlanets();
	}

	public void handle() {
		//handleKeys();
		for(Planet planet: planets){
			if(checkVisible(planet))
				planet.onVisible();
			else
				planet.onInvisible();
		}
		checkSelectionAndFocus(planets);
		checkDragBetweenObjects();
		checkArgessivitnessChange();
	}

	private boolean checkVisible(Planet planet) {
		// TODO: Can be simply optimized by determination of a direction vector
		// that goes from center of the camera to center of the planet.
		// Next, this vector should be passed to pickPoligon method instead of
		// return value from reproject2D3D.
		SimpleVector planetProjection = Interact2D.projectCenter3D2D(
				world.getCamera(), buffer, planet.getBoundingSphere());

		if (planetProjection != null) {
			if (planet.getBoundingSphere().getID() == Interact2D.getObjectID(Interact2D.pickPolygon(
					world.getVisibilityList(), Interact2D.reproject2D3D(world.getCamera(), buffer,(int) planetProjection.x, (int) planetProjection.y))))
				return true;
		}
		return false;
	}
	
	private void checkSelectionAndFocus(List<Planet> planets){
		SimpleVector mouse3DPos = Interact2D.reproject2D3D(world.getCamera(), buffer, Mouse.getX(), Mouse.getY());
		mouse3DPos.y = -mouse3DPos.y;
		int focusedObjectID = Interact2D.getObjectID(Interact2D.pickPolygon(world.getVisibilityList(), mouse3DPos));
		if(focusedObjectID != -1){
			if(focusedPlanet == null || focusedObjectID != focusedPlanet.getBoundingSphere().getID()){
				for(Planet planet : planets){
					if(planet.getBoundingSphere().getID() == focusedObjectID){
						checkPlanetFocus(planet);
						checkPlanetSelect(planet);
					}
				}
			}
			else{
				checkPlanetSelect(focusedPlanet);
			}
		}
		else{
			if(focusedPlanet != null){
				focusedPlanet.onFocusLoss();
				focusedPlanet = null;
			}
		}
	}

	private void checkPlanetFocus(Planet planet){
		if(focusedPlanet != null){
			focusedPlanet.onFocusLoss();
		}
		focusedPlanet = planet;	
		planet.onFocus();	
	}

	private void checkPlanetSelect(Planet planet){
		if(Mouse.isButtonDown(0)){
			if(selectedPlanet != null){
				selectedPlanet.onRelease();
			}
			selectedPlanet = planet;
			planet.onSelect();
		}
	}
	
	private void checkDragBetweenObjects(){
		if(Mouse.isButtonDown(0) && srcDragId == -1){
			srcDragId = getFocusedObjectId();
		}
		if(!Mouse.isButtonDown(0)){
			if(srcDragId != -1){
				int objectId = getFocusedObjectId();
				if(objectId == srcDragId || objectId == -1){
					srcDragId = -1;
				} else {
					raiseDragBetweenPlanetsEvent(srcDragId, objectId);
					srcDragId = -1;
				}
			}
		}
	}
	
	private void raiseDragBetweenPlanetsEvent(int srcDragId, int destDragId){
		Planet srcPlanet = null, destPlanet = null;
		for(Planet planet : planets){
			if(planet.getBoundingSphere().getID() == srcDragId)
				srcPlanet = planet;
			else if(planet.getBoundingSphere().getID() == destDragId)
				destPlanet = planet;
		}
		
		if(srcPlanet != null && destPlanet != null)
			universe.onDragBetweenPlanets(srcPlanet, destPlanet);
	}
	
	private int getFocusedObjectId(){
		SimpleVector mouse3DPos = Interact2D.reproject2D3D(world.getCamera(), buffer, Mouse.getX(), Mouse.getY());
		mouse3DPos.y = -mouse3DPos.y;
		return Interact2D.getObjectID(Interact2D.pickPolygon(world.getVisibilityList(), mouse3DPos));
	}
	
	private void checkArgessivitnessChange(){
		if(Keyboard.KEY_1)
			universe.onAggressivnessChange(0.1f);
		else if(Keyboard.KEY_2)
			universe.onAggressivnessChange(0.2f);
		else if(Keyboard.KEY_3)
			universe.onAggressivnessChange(0.3f);
		else if(Keyboard.KEY_4)
			universe.onAggressivnessChange(0.4f);
		else if(Keyboard.KEY_5)
			universe.onAggressivnessChange(0.5f);
		else if(Keyboard.KEY_6)
			universe.onAggressivnessChange(0.6f);
		else if(Keyboard.KEY_7)
			universe.onAggressivnessChange(0.7f);
		else if(Keyboard.KEY_8)
			universe.onAggressivnessChange(0.8f);
		else if(Keyboard.KEY_9)
			universe.onAggressivnessChange(0.9f);
		else if(Keyboard.KEY_0)
			universe.onAggressivnessChange(1.0f);
	}
}
